#include "GameManager.h"
#include "RandomSystem.h"
#include "GameSettings.h"
#include "AuctionManager.h"
#include "PlayerManager.h"
#include "TeamManager.h"
#include "LeagueManager.h"
#include "UserManager.h"
#include "NameManager.h"
#include "Events.h"
#include "ZStream.h"
#include "GameAI.h"

#include <fstream>
//#include <ctime>

GameManager::GameManager()
{
	m_seed = InitRandomSystem();

	m_settings = new Settings;
	m_settings->Load("./settings.txt");

	m_nameManager = new NameManager;
	m_auctionManager = new AuctionManager(this);
	m_teamManager = new TeamManager(this);
	m_playerManager = new PlayerManager(this);
	m_leagueManager = new LeagueManager(this);
	m_userManager = new UserManager(this);
	m_ai = new GameAI(this);
	m_matchEventGenerator = new EventGenerator("match_events.txt");
}

GameManager::~GameManager()
{
	Clear();

	delete m_matchEventGenerator;
	delete m_ai;
	delete m_userManager;
	delete m_leagueManager;
	delete m_playerManager;
	delete m_teamManager;
	delete m_auctionManager;
	delete m_nameManager;
	delete m_settings;
}

void GameManager::Initialize()
{
	ZStream file;
	file.Open("./leagueSettings.txt", std::ios_base::in);
	LeagueManagerSettings settings;
	settings.Deserialize(file);
	file.Close();

	GetPlayerMgr().Initialize();
	GetTeamMgr().Initialize();
	GetLeagueMgr().Initialize(settings);
	GetAI().AssignPlayersOnTeams(GetLeagueMgr().GetLeagues(false));
	GetAuctionMgr().CreateNewMarket(GetSettings().GetValue("I_MAX_MARKET_PLAYERS_IN_SEASON").Get<size_t>());
}

void GameManager::PreMatchUpdate(const bool i_doNotPrompt)
{
	// Pre-Match AI Update: market and formations
	GetAI().PreMatchUpdate(i_doNotPrompt);
}

void GameManager::Update(const bool i_doNotPrompt)
{	
	// League Manager Update
	GetLeagueMgr().Update(i_doNotPrompt);
}

void GameManager::PostMatchUpdate(const bool i_doNotPrompt)
{
	// Team Manager Update: money (now in match, to be moved)
	GetTeamMgr().Update();
	
	// Player Manager Update: free players must be updated (fatiguee update, inj update)
	GetPlayerMgr().Update();

	// Player Offers Resolution
	GetAuctionMgr().Dispatch(i_doNotPrompt);
	
	// Market Management
	GetAuctionMgr().CreateNewMarket(GetSettings().GetValue("I_MAX_MARKET_PLAYERS_IN_SEASON").Get<size_t>());

	// Post-Match AI Update: make formations (not necessary, just to debug-view how the team)
	GetAI().PostMatchUpdate();
}

void GameManager::Simulate(const bool i_doNotPrompt)
{
	//clock_t clock0 = clock();
	PreMatchUpdate(i_doNotPrompt);

	//clock_t clock1 = clock();
	//clock_t time1 = clock1 - clock0;
	Update(i_doNotPrompt);

	//clock_t clock2 = clock();
	//clock_t time2 = clock2 - clock1;
	PostMatchUpdate(i_doNotPrompt);

	//clock_t clock3 = clock();
	//clock_t time3 = clock3 - clock2;
	if(!i_doNotPrompt)
		system("pause");
	//else
	//	std::cout << time1 << "  " << time2 << "  " << time3 << std::endl;
}

void GameManager::EndSeason(const bool i_doNotPrompt, std::stringstream& o_message)
{
	GetLeagueMgr().EndSeasonUpdate(i_doNotPrompt, o_message);
	GetAuctionMgr().CreateNewMarket(GetSettings().GetValue("I_MAX_MARKET_PLAYERS_IN_SEASON").Get<size_t>());
}

void GameManager::Clear()
{
	GetLeagueMgr().Clear();
	GetPlayerMgr().Clear();
	GetTeamMgr().Clear();
	GetNameMgr().Clear();
	GetAuctionMgr().Clear();
	GetUserMgr().Clear();
}

void GameManager::Restart()
{
	Clear();

	Initialize();
}

bool GameManager::Load(const char* const filename)
{
	ZStream file;

	if(!file.Open(filename, std::fstream::in))
		return false;

	Clear();

	size_t leagueNum;
	file.ReadAttribute(leagueNum);
	file.ReadAttribute(m_seed);

	size_t usersNum;
	file.ReadAttribute(usersNum);

	size_t lastTeamID, lastPlayerID;

	file.ReadAttribute(lastTeamID);
	file.ReadAttribute(lastPlayerID);

	GetPlayerMgr().Initialize(lastPlayerID);
	GetTeamMgr().Initialize(lastTeamID);

	LeagueManagerSettings settings;
	settings.Deserialize(file);

	GetLeagueMgr().Initialize(settings);

	GetLeagueMgr().Deserialize(file);

	for(size_t i = 0; i < usersNum; ++i)
	{
		GetUserMgr().AddUser("");
		GetUserMgr().GetUserList().back()->Deserialize(file);
	}

	GetAuctionMgr().Deserialize(file);

	return true;
}

bool GameManager::Save(const char* const filename)
{
	ZStream file;
	if(!file.Open(filename, std::fstream::out | std::fstream::trunc))
		return false;

	file.WriteAttribute("LeaguesNum", GetLeagueMgr().GetNumOfLeagues(false));
	file.WriteAttribute("Seed", m_seed);
	file.WriteAttribute("UsersNum", GetUserMgr().GetUserList().size());
	file.WriteAttribute("LastPlayerID", GetPlayerMgr().GetLastID());
	file.WriteAttribute("LastTeamID", GetTeamMgr().GetLastID());

	GetLeagueMgr().GetSettings().Serialize(file);

	GetLeagueMgr().Serialize(file);

	for(size_t i = 0; i < GetUserMgr().GetUserList().size(); ++i)
		GetUserMgr().GetUserList()[i]->Serialize(file);

	GetAuctionMgr().Serialize(file);

	return true;
}

